//
// Created by Administrator on 2020/1/7.
//

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "share_memory.h"
#include "../include/log_utils.h"

#include <linux/ashmem.h>

#define ASHMEM_DEVICE  "/dev/ashmem"

#define U64 int



//ret= 0 创建成功；ret=-1，失败；
//注：ret =1，共享内存已经存在，但是目前这个没用，暂时放这
int create_shared_memory(const char* name, U64 size, int node, char*& addr, U64& shm_id){
    int fd = open(ASHMEM_DEVICE, O_RDWR);
    if(fd < 0){
        return -1;
    }
    U64 len = ioctl(fd, ASHMEM_GET_SIZE, NULL);
    if(len > 0){
        addr = (char*)mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        shm_id = fd;
        return 1;
    }else{
        int ret = ioctl(fd, ASHMEM_SET_NAME,name);
        if(ret < 0){
            close(fd);
            return -1;
        }
        ret = ioctl(fd,ASHMEM_SET_SIZE, size);
        if(ret < 0){
            close(fd);
            return -1;
        }
        addr = (char*)mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        shm_id = fd;
    }
    return 0;
}

int open_shared_memory(const char* name, int node, char*& addr, U64& shm_id){
    U64 size = ioctl(shm_id, ASHMEM_GET_SIZE,NULL);
    if(size > 0){
        addr = (char*)mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0);
    }else{
        return -1;
    }
    return 0;
}

int close_shared_memory(U64& shm_id, char*& addr){
    U64 size = ioctl(shm_id, ASHMEM_GET_SIZE, NULL);
    if(size <0){
        return -1;
    }
    int ret = munmap((void*)addr, size);
    if(ret == -1){
        return -1;
    }
    ret = close(shm_id);
    if(ret == -1){
        return -1;
    }
    return 0;
}

SharedMemory* SharedMemory::Create(const std::string &name) {
    int dev_fd = open(ASHMEM_DEVICE, O_RDWR);
    if(dev_fd<0){
        AKLogErr("fail to open ashmem device\n");
        return nullptr;
    }
    return new SharedMemory(dev_fd,name);
}

bool SharedMemory::SetName(const std::string &name) {
    const char* p_name=name.c_str();
    int ret = ioctl(mFD, ASHMEM_SET_NAME,p_name);
    if(ret < 0){
        close(mFD);
        return false;
    }
    AKLog("shared memory %d name set to %s\n",mFD,p_name);
    return true;
}

SharedMemory::SharedMemory(int fd, const std::string &name) {
    mFD=fd;
    mName=name;
}

bool SharedMemory::SetSize(int size) {
    int ret = ioctl(mFD,ASHMEM_SET_SIZE, size);
    if(ret < 0){
        close(mFD);
        return false;
    }
    AKLog("shared memory %d size\n",mFD);
    return true;
}

void *SharedMemory::DoAlloc() {
    int size=GetSize();
    AKLog("attempt to alloc shared memory %d sized %d\n",mFD,size);
    void* address = mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, mFD, 0);
    AKLog("shared memory address:%p\n",address);
    return address;
}

int SharedMemory::GetSize() {
    return ioctl(mFD, ASHMEM_GET_SIZE, NULL);
}
